Passed
Push — master ( 138b3f...4f5721 )
by Rafael S.
01:29
created

BitDepthFunctions.floatToFloat   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 2
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
/*!
2
 * bitdepth
3
 * Change the bit depth of samples to and from 8, 16, 24, 32 & 64-bit.
4
 * Copyright (c) 2017 Rafael da Silva Rocha.
5
 * https://github.com/rochars/bitdepth
6
 *
7
 */
8
9
const f64f32 = new Float32Array(1);
10
11
/**
12
 * Max number of different values for each bit depth.
13
 * @enum {number}
14
 */
15
const MAX_VALUES = {
16
    "8": 256,
17
    "16": 65536,
18
    "24": 16777216,
19
    "32": 4294967296,
20
    "32f": 1,
21
    "64": 1
22
};
23
24
/**
25
 * Functions to change the bit depth of a sample.
26
 */
27
const BitDepthFunctions = {
28
29
    /**
30
     * Change the bit depth from int to int.
31
     * @param {number} sample The sample.
32
     * @param {Object} args Data about the original and target bit depths.
33
     * @return {number}
34
     */
35
    "intToInt": function(sample, args) {
36
        if (sample > 0) {
37
            sample = parseInt(
38
                (sample / args["oldPositive"]) * args["newPositive"], 10);
39
        } else {
40
            sample = parseInt(
41
                (sample / args["oldNegative"]) * args["newNegative"], 10);
42
        }
43
        return sample;
44
    },
45
46
    /**
47
     * Change the bit depth from float to int.
48
     * @param {number} sample The sample.
49
     * @param {Object} args Data about the original and target bit depths.
50
     * @return {number}
51
     */
52
    "floatToInt": function(sample, args) {
53
        return sample > 0 ?
54
            sample * args["newPositive"] : sample * args["newNegative"];
55
    },
56
57
    /**
58
     * Change the bit depth from int to float.
59
     * @param {number} sample The sample.
60
     * @param {Object} args Data about the original and target bit depths.
61
     * @return {number}
62
     */
63
    "intToFloat": function(sample, args) {
64
        return sample > 0 ?
65
            sample / args["oldPositive"] : sample / args["oldNegative"];
66
    },
67
68
    /**
69
     * Change the bit depth from float to float.
70
     * @param {number} sample The sample.
71
     * @param {Object} args Data about the original and target bit depths.
72
     * @return {number}
73
     */
74
    "floatToFloat": function(sample, args) {
75
        if (args["original"] == "64" && args["target"] == "32f") {
76
            f64f32[0] = sample;
77
            sample = f64f32[0];
78
        }
79
        return sample;
80
    }
81
};
82
83
/**
84
 * Change the bit depth of the data in a array.
85
 * The input array is modified in-place.
86
 * @param {!Array<number>} samples The samples.
87
 * @param {string} originalBitDepth The original bit depth of the data.
88
 *      One of "8", "16", "24", "32", "32f", "64"
89
 * @param {string} targetBitDepth The new bit depth of the data.
90
 *      One of "8", "16", "24", "32", "32f", "64"
91
 */
92
function toBitDepth(samples, originalBitDepth, targetBitDepth) {
93
    validateBitDepths_(originalBitDepth, targetBitDepth);
94
    let toFunction = getBitDepthFunction_(originalBitDepth, targetBitDepth);
95
    let len = samples.length;
96
    for (let i=0; i<len; i++) {        
97
        samples[i] = sign8Bit_(samples[i], originalBitDepth);
98
        samples[i] = toFunction(
99
                samples[i],
100
                {
101
                    "oldNegative": MAX_VALUES[originalBitDepth] / 2,
102
                    "newNegative": MAX_VALUES[targetBitDepth] / 2,
103
                    "oldPositive": MAX_VALUES[originalBitDepth] / 2 - 1,
104
                    "newPositive": MAX_VALUES[targetBitDepth] / 2 - 1,
105
                    "original": originalBitDepth,
106
                    "target": targetBitDepth
107
                }
108
            );
109
        samples[i] = unsign8Bit_(samples[i], targetBitDepth);
110
    }
111
}
112
113
/**
114
 * Get the function to change the bit depth of a sample.
115
 * @param {string} originalBitDepth The original bit depth of the data.
116
 *      One of "8", "16", "24", "32", "32f", "64"
117
 * @param {string} targetBitDepth The new bit depth of the data.
118
 *      One of "8", "16", "24", "32", "32f", "64"
119
 * @return {Function}
120
 */
121
function getBitDepthFunction_(originalBitDepth, targetBitDepth) {
122
    let prefix;
123
    let suffix;
124
    if (["32f", "64"].includes(originalBitDepth)) {
125
        prefix = "float";
126
    } else {
127
        prefix = "int";
128
    }
129
    if (["32f", "64"].includes(targetBitDepth)) {
130
        suffix = "Float";
131
    } else {
132
        suffix = "Int";
133
    }
134
    return BitDepthFunctions[prefix + "To" + suffix];
135
}
136
137
/**
138
 * Sign unsigned 8-bit data.
139
 * @param {number} sample The sample.
140
 * @param {string} originalBitDepth The original bit depth of the data.
141
 *      One of "8", "16", "24", "32", "32f", "64"
142
 * @return {number}
143
 */
144
function sign8Bit_(sample, originalBitDepth) {
145
    if (originalBitDepth == "8") {
146
        sample -= 128;
147
    }
148
    return sample;
149
}
150
151
/**
152
 * Unsign signed 8-bit data.
153
 * @param {number} sample The sample.
154
 * @param {string} targetBitDepth The target bit depth of the data.
155
 *      One of "8", "16", "24", "32", "32f", "64"
156
 * @return {number}
157
 */
158
function unsign8Bit_(sample, targetBitDepth) {
159
    if (targetBitDepth == "8") {
160
        sample += 128;
161
    }
162
    return sample;
163
}
164
165
/**
166
 * Validate the bit depth.
167
 * @param {string} originalBitDepth The original bit depth.
168
 *     Should be one of "8", "16", "24", "32", "32f", "64".
169
 * @param {string} targetBitDepth The target bit depth.
170
 *     Should be one of "8", "16", "24", "32", "32f", "64".
171
 * @throws {Error} If any argument does not meet the criteria.
172
 * @return {boolean}
173
 */
174
function validateBitDepths_(originalBitDepth, targetBitDepth) {
175
    let validBitDepths = ["8", "16", "24", "32", "32f", "64"];
176
    if (validBitDepths.indexOf(originalBitDepth) == -1 ||
177
        validBitDepths.indexOf(targetBitDepth) == -1) {
178
        throw new Error("Invalid bit depth.");
179
    }
180
    return true;
181
}
182
183
module.exports.toBitDepth = toBitDepth;
184
module.exports.BitDepthMaxValues = MAX_VALUES;
185